/**
 * @author		Ben Layet
 * @version 	1.0
 * @date		25 Sep 2008
 */
package org.ignoramus.application.store;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * The XML Cards data parser.
 */
public class CardsParser
{
	/** information tag. */
	private static final String	information_tag	= "information";
	/** card tag. */
	private static final String	card_tag		= "card";
	/** id attribute. */
	private static final String	id_attribute	= "id";
	/** name attribute. */
	private static final String	name_attribute	= "name";

	/** The input stream data. */
	private final InputStream	data;

	/** The Cards data. */
	private Map<String, Map<String, String>>				cards			= null;

	/**
	 * Constructs with the input stream data.
	 * 
	 * @param data
	 *            the input stream data.
	 */
	public CardsParser(InputStream data)
	{
		this.data = data;
	}

	/**
	 * parses the file.
	 * 
	 * @throws StoreException
	 *             if the file cannot be parsed.
	 */
	private void parse() throws StoreException
	{
		// check if it has already been parsed
		if (cards == null)
		{
			cards = new LinkedHashMap<String, Map<String,String>>();
			// document builder factory
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			try
			{
				// document builder
				DocumentBuilder db = dbf.newDocumentBuilder();
				// parse the document
				Document doc = db.parse(data);
				// normalise the document
				doc.getDocumentElement().normalize();
				
				// get the card elements
				NodeList cardNodes = doc.getElementsByTagName(card_tag);
				//loop through the card nodes
				for (int i = 0; i < cardNodes.getLength(); i++)
				{
					//the card
					Map<String, String> card = new HashMap<String, String>();
					
					//get the next card element
					Element cardElement = (Element) cardNodes.item(i);
					//get the card id
					String cardId = cardElement.getAttribute(id_attribute);
					
					//add the card to the cards
					cards.put(cardId, card);
					
					// get the card elements
					NodeList infoNodes = cardElement.getElementsByTagName(information_tag);
					//loop through the card nodes
					for (int j = 0; j < infoNodes.getLength(); j++)
					{
						//get the next information element
						Element infoElement = (Element) infoNodes.item(j);
						//get the information name
						String name = infoElement.getAttribute(name_attribute);
						//get the information value
						String value = infoElement.getTextContent();
						
						//add the piece of information to the card
						card.put(name, value);
						
					}
				}
				
				// close the input stream
				data.close();

			}
			catch (ParserConfigurationException e)
			{
				throw new StoreException("Cannot parse the lesson file.", e);
			}
			catch (SAXException e)
			{
				throw new StoreException("Cannot parse the lesson file.", e);
			}
			catch (IOException e)
			{
				throw new StoreException("Cannot parse the lesson file.", e);
			}
		}
	}

	/**
	 * @returns the cards.
	 * @throws StoreException
	 *             if the file cannot be parsed.
	 */
	public Map<String, Map<String,String>> getCards() throws StoreException
	{
		parse();
		return cards;
	}

}
